package com.ygqh.baby.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.foxinmy.weixin4j.api.Pay3Api;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.exception.WeixinPayException;
import com.foxinmy.weixin4j.http.weixin.WeixinRequestExecutor;
import com.foxinmy.weixin4j.model.WeixinPayAccount;
import com.foxinmy.weixin4j.mp.token.WeixinTokenCreator;
import com.foxinmy.weixin4j.payment.PayRequest;
import com.foxinmy.weixin4j.payment.mch.PrePay;
import com.foxinmy.weixin4j.payment.mch.RefundResult;
import com.foxinmy.weixin4j.token.TokenHolder;
import com.foxinmy.weixin4j.type.*;
import com.foxinmy.weixin4j.util.DigestUtil;
import com.foxinmy.weixin4j.util.StringUtil;
import com.ygqh.baby.ao.AppType;
import com.ygqh.baby.ao.FileType;
import com.ygqh.baby.constant.Constant;
import com.ygqh.baby.exception.YgException;
import com.ygqh.baby.po.YgPlatform;
import com.ygqh.baby.service.*;
import com.ygqh.baby.service.wechat.api.YgPay3Api;
import com.ygqh.baby.service.wechat.model.WxPayAccount;
import com.ygqh.baby.service.wechat.notify.YgMchPayPackage;
import com.ygqh.baby.service.wechat.util.Configure;
import com.ygqh.baby.utils.CommonUtil;
import com.ygqh.baby.utils.HttpUtil;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;

@Service
public class WxSmallAuthorityServiceImpl implements WxSmallAuthorityService {

    protected final Logger logger = Logger.getLogger(this.getClass());
    protected final static WeixinRequestExecutor weixinExecutor;
    @Value("${micro.msg.appId}")
    private String providerAppId;

    @Value("${small.appId}")
    private String appId;
    @Value("${small.secret}")
    private String secret;
    @Value("${small.key}")
    private String key;
    @Value("${small.mchId}")
    private String mchId;
    @Value("${wechat.pay.notify_url}")
    private String notify_url;
    @Autowired
    private WxSmallTokenStorager tokenStorager;
    @Autowired
    private FileService fileService;
    @Autowired
    private YgPlatformService ygPlatformService;
    @Value("${image.domain}")
    private String imageDomain;
    @Value("${message.send}")
    private Boolean sendMsg;


    @Autowired
    private YgOrderPayLogService ygOrderPayLogService;

    static {
        weixinExecutor = new WeixinRequestExecutor();
    }

    @Override
    public TokenHolder findTokenHolder() {
        WeixinTokenCreator weixinTokenCreator = new WeixinTokenCreator(appId, secret);
        TokenHolder tokenHolder = new TokenHolder(weixinTokenCreator, tokenStorager);
        return tokenHolder;
    }

	@Override
	public TokenHolder findTokenHolder(String platformNo) {
        if (!sendMsg) {
            return null;
        }
        if (StringUtils.isBlank(platformNo) || Constant.YIIGOO_PLATFORM_NO.equals(platformNo)) {
            return this.findTokenHolder();
        }
        YgPlatform platform = ygPlatformService.findByPlatformNo(platformNo, AppType.Small);
        WeixinTokenCreator weixinTokenCreator = new WeixinTokenCreator(platform.getAppId(), platform.getSecret());
        return new TokenHolder(weixinTokenCreator, tokenStorager);
	}

	@Override
    public String getSamllQrcode(String url, int shape) {
         return getSamllQrcode(url, shape, this.findTokenHolder());
    }

    @Override
    public String getSamllQrcode(String url, int shape, String platformNo) {
        TokenHolder tokenHolder = findTokenHolder(platformNo);
        return getSamllQrcode(url, shape, tokenHolder);
    }

    /**
     * @param url 小程序page
     * @param shape (0和1的情况，数量加起来最多 100,000)
     *       0: 获取小程序二维码（不推荐使用）可接受 path 参数较长，生成个数受限
     *       1: 获取小程序码, 可接受 path 参数较长，生成个数受限
     *       2: 生成小程序码，可接受页面参数较短，生成个数不受限 (频率受限5000次/分钟)(不支持符号%，不支持中文传参，若要传中文需以其它编码解码的方式)
     * @param tokenHolder tokenHolder
     * @return
     */
    private String getSamllQrcode(String url, int shape, TokenHolder tokenHolder) {
        String api = null;
        JSONObject obj = new JSONObject();
        if (shape == 0) {
            api = "https://api.weixin.qq.com/cgi-bin/wxaapp/createwxaqrcode?access_token=%s";
        } else if (shape == 1) {
            api = "https://api.weixin.qq.com/wxa/getwxacode?access_token=%s";
        } else if (shape == 2) {
            api = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=%s";
            int index = url.indexOf("?");
            String scene = "";
            if (index != -1) {
                scene = url.substring(index + 1, url.length());
                url = url.substring(0, index);
            }
            obj.put("scene", scene);
        }
        obj.put("path", url);
        obj.put("width", 430);
        try {
            InputStream is = HttpUtil.con_post$io(String.format(api, tokenHolder.getAccessToken()), obj.toString());
            ByteArrayOutputStream bytestream = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int ch;
            while ((ch = is.read(buffer)) != -1) {
                bytestream.write(buffer, 0, ch);
            }
            //
            byte data[] = bytestream.toByteArray();
            String originalFileName = System.currentTimeMillis() + "" + CommonUtil.generatorSmsValidateCode();
            String key = fileService.getUploadImageKey(FileType.QrCode, "samllQrCode.jpg", originalFileName);
            fileService.upload2Oss(key, data);
            return imageDomain + key;
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        return null;
    }

    @Override
    public PayRequest createPrePay(String openId, Long paymentCode, int totalFee, String ipAddress) throws WeixinPayException {
        return this.createPrePay(openId, paymentCode, totalFee, ipAddress, notify_url, null, null);
    }

    @Override
    public PayRequest createPrePay(String openId, Long paymentCode, int totalFee, String ipAddress, String notifyUrl, String attach, String goodsTag)
            throws WeixinPayException {
        WeixinPayAccount weixinAccount = new WeixinPayAccount(appId, secret, key, mchId);
        System.out.println(appId + ";" + secret + ";" + key + ";" + mchId + ";" + openId + ";" + goodsTag);
        YgMchPayPackage payPackage = new YgMchPayPackage(weixinAccount, openId, "壹果订单", paymentCode.toString(), totalFee, notifyUrl, ipAddress,
                TradeType.JSAPI);
        if (StringUtil.isNotBlank(attach)) {
            payPackage.setAttach(attach);
        }
        if (StringUtil.isNotBlank(goodsTag)) {
            payPackage.setGoodsTag(goodsTag);
        }
        YgPay3Api ygPay3Api = new YgPay3Api(weixinAccount);
        ygPay3Api.setYgOrderPayLogService(ygOrderPayLogService);
        PrePay prePay = ygPay3Api.createPrePay(payPackage);
        PayRequest payRequest = new PayRequest(prePay.getAppId(), "prepay_id=" + prePay.getPrepayId());
        payRequest.setPrepayId(prePay.getPrepayId());
        payRequest.setSignType(SignType.MD5);
        payRequest.setPaySign(DigestUtil.paysignMd5(payRequest, Configure.getSmallkey()));
        return payRequest;
    }

    @Override
    public RefundResult refund(String returnCode, BigDecimal refundPrice, BigDecimal orderPrice, String orderPayCode) throws YgException {

        RefundResult result = null;
        try {
            InputStream inputStream = fileService.downloadIOFromOss("cert/small/apiclient_cert.p12");

            WeixinPayAccount weixinAccount = new WeixinPayAccount(appId, secret, key, mchId);
            Pay3Api pay3Api = new Pay3Api(weixinAccount);
            IdQuery idQuery = new IdQuery(orderPayCode, IdType.TRADENO);
            result = pay3Api.refundApply(inputStream, idQuery, returnCode, orderPrice.doubleValue(), refundPrice.doubleValue(), CurrencyType.CNY, mchId);

        } catch (Exception e) {
            YgException exception = null;
            e.printStackTrace();
            if (e instanceof WeixinException) {
                exception = new YgException(((WeixinException) e).getErrorCode(), ((WeixinException) e).getErrorMsg());
                System.out.println(exception.getMessage());
            } else if (e instanceof IOException) {
                exception = new YgException("读取证书失败", e.toString());
            } else {
                exception = new YgException(e.getMessage());
            }
            throw exception;
        }
        return result;

    }

    @Override
    public PayRequest createPrePayByProvider(String platformNo, String subOpenId, Long paymentCode, int totalFee, String ipAddress, String notifyUrl,
                                             String attach) throws WeixinPayException {

        WxPayAccount wxPayAccount = this.getWxPayAccount(platformNo);
        YgMchPayPackage payPackage = new YgMchPayPackage(wxPayAccount, null, subOpenId, "壹果订单", paymentCode.toString(), totalFee, notifyUrl, ipAddress,
                TradeType.JSAPI, attach);
        payPackage.setSubOpenId(subOpenId);

        YgPay3Api ygPay3Api = new YgPay3Api(wxPayAccount);
        PrePay prePay = ygPay3Api.createPrePay(payPackage);
        PayRequest payRequest = new PayRequest(prePay.getAppId(), "prepay_id=" + prePay.getPrepayId());
        payRequest.setPrepayId(prePay.getPrepayId());
        payRequest.setSignType(SignType.MD5);
        payRequest.setPaySign(DigestUtil.paysignMd5(payRequest, Configure.getSmallkey()));
        return payRequest;
    }

    @Override
    public RefundResult refundByProvider(String platformNo, String returnCode, BigDecimal refundPrice, BigDecimal orderPrice, String orderPayCode)
            throws YgException {

        RefundResult result = null;
        try {
            InputStream inputStream = fileService.downloadIOFromOss("cert/platform/apiclient_cert.p12");

            WxPayAccount wxPayAccount = getWxPayAccount(platformNo);
            YgPay3Api pay3Api = new YgPay3Api(wxPayAccount);
            IdQuery idQuery = new IdQuery(orderPayCode, IdType.TRADENO);
            result = pay3Api.refundByProvider(inputStream, idQuery, returnCode, orderPrice.doubleValue(), refundPrice.doubleValue());

        } catch (Exception e) {
            YgException exception = null;
            e.printStackTrace();
            if (e instanceof WeixinException) {
                exception = new YgException(((WeixinException) e).getErrorCode(), ((WeixinException) e).getErrorMsg());
                System.out.println(exception.getMessage());
            } else if (e instanceof IOException) {
                exception = new YgException("读取证书失败", e.toString());
            } else {
                exception = new YgException(e.getMessage());
            }
            throw exception;
        }
        return result;

    }

    private WxPayAccount getWxPayAccount(String platformNo) {
        YgPlatform platform = ygPlatformService.findByPlatformNo(platformNo);
        providerAppId = "wx563327e8dd35e422";
        WxPayAccount weixinPayAccount = new WxPayAccount(providerAppId, null, platform.getPaySignKey(), platform.getMchId(), platform.getAppId(),
                platform.getSubMchId());
        return weixinPayAccount;

    }


}
